﻿/********************************************************************************
    Copyright (C) Binod Nepal, Planet Earth Solutions Pvt. Ltd., Kathmandu.
	Released under the terms of the GNU General Public License, GPL, 
	as published by the Free Software Foundation, either version 3 
	of the License, or (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
***********************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using Pes.Messaging.ApplicationLayer;
using System.IO;
using log4net.Appender;
using log4net;
using log4net.Config;

namespace Pes.Messaging.Service
{
    public partial class MessagingService : ServiceBase
    {
        int counter;
        bool stop;
        int pollInterval;


        public MessagingService()
        {
            BasicConfigurator.Configure();

            log4net.Config.XmlConfigurator.Configure();

            this.ServiceName = "PES Messaging Services";
            this.EventLog.Log = "Application";

            this.CanHandlePowerEvent = true;
            this.CanHandleSessionChangeEvent = true;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.CanStop = true;

            pollInterval = Pes.Messaging.ApplicationLayer.Program.GetPollInterval();
            counter = 0;
            InitializeComponent();
            if (!EventLog.SourceExists(this.ServiceName))
            {
                EventLog.CreateEventSource(this.ServiceName, "Application");            
            }
        }

        protected void Worker(object stateInfo)
        {
            try
            {
                counter++;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine();
                Console.WriteLine("................................................................................");
                Console.WriteLine();
                LogProvider.log.DebugFormat("{0} The worker thread is now invoked.", counter.ToString("000"));
                Pes.Messaging.ApplicationLayer.Program.StartWork();
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                LogProvider.log.Error(ex.Message);

                stop = true;
                //Stop the service.
                this.Stop();
            }
        }


        /// <summary>
        /// OnStart(): Put startup code here
        ///  - Start threads, get inital data, etc.
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            Trace.Listeners.Clear();

            TextWriterTraceListener twtl = new TextWriterTraceListener(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName));
            twtl.Name = "TextLogger";
            twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;

            ConsoleTraceListener ctl = new ConsoleTraceListener(false);
            ctl.TraceOutputOptions = TraceOptions.DateTime;

            Trace.Listeners.Add(twtl);
            Trace.Listeners.Add(ctl);
            Trace.AutoFlush = true;


            Console.ForegroundColor = ConsoleColor.Cyan;
            LogProvider.log.InfoFormat("{0} was started.", this.ServiceName);
            stop = false;
            this.StartWork();
            base.OnStart(args);
        }

        private void StartWork()
        {
            Worker(null);
            using (new Timer(Worker, null, TimeSpan.FromSeconds(pollInterval), TimeSpan.FromSeconds(pollInterval)))
            {
                while (true)
                {
                    if (stop)
                    {
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// OnStop(): Put your stop code here
        /// - Stop threads, set final data, etc.
        /// </summary>
        protected override void OnStop()
        {
            stop = true;
            Console.ForegroundColor = ConsoleColor.Red;
            LogProvider.log.WarnFormat("{0} was stopped.", this.ServiceName);

            base.OnStop();
        }

        /// <summary>
        /// OnPause: Put your pause code here
        /// - Pause working threads, etc.
        /// </summary>
        protected override void OnPause()
        {
            stop = true;
            Console.ForegroundColor = ConsoleColor.Gray;
            LogProvider.log.WarnFormat("{0} was paused.", this.ServiceName);
            base.OnPause();
        }

        /// <summary>
        /// OnContinue(): Put your continue code here
        /// - Un-pause working threads, etc.
        /// </summary>
        protected override void OnContinue()
        {
            stop = false;
            this.StartWork();

            Console.ForegroundColor = ConsoleColor.Green;
            LogProvider.log.InfoFormat("{0} was resumed.", this.ServiceName);
            base.OnContinue();
        }

        /// <summary>
        /// OnShutdown(): Called when the System is shutting down
        /// - Put code here when you need special handling
        ///   of code that deals with a system shutdown, such
        ///   as saving special data before shutdown.
        /// </summary>
        protected override void OnShutdown()
        {
            stop = true;
            Console.ForegroundColor = ConsoleColor.Red;
            LogProvider.log.InfoFormat("{0} was closed.", this.ServiceName);
            base.OnShutdown();
        }

        /// <summary>
        /// OnCustomCommand(): If you need to send a command to your
        ///   service without the need for Remoting or Sockets, use
        ///   this method to do custom methods.
        /// </summary>
        /// <param name="command">Arbitrary Integer between 128 & 256</param>
        protected override void OnCustomCommand(int command)
        {
            //  A custom command can be sent to a service by using this method:
            //#  int command = 128; //Some Arbitrary number between 128 & 256
            //#  ServiceController sc = new ServiceController("NameOfService");
            //#  sc.ExecuteCommand(command);

            base.OnCustomCommand(command);
        }

        /// <summary>
        /// OnPowerEvent(): Useful for detecting power status changes,
        ///   such as going into Suspend mode or Low Battery for laptops.
        /// </summary>
        /// <param name="powerStatus">The Power Broadcast Status
        /// (BatteryLow, Suspend, etc.)</param>
        protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
        {
            Console.ForegroundColor = ConsoleColor.DarkRed;
            LogProvider.log.WarnFormat("{0} had a power event {1}.", this.ServiceName, powerStatus.ToString());
            return base.OnPowerEvent(powerStatus);
        }

        /// <summary>
        /// OnSessionChange(): To handle a change event
        ///   from a Terminal Server session.
        ///   Useful if you need to determine
        ///   when a user logs in remotely or logs off,
        ///   or when someone logs into the console.
        /// </summary>
        /// <param name="changeDescription">The Session Change
        /// Event that occured.</param>
        protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            LogProvider.log.WarnFormat("{0} had a session change with reason '{1}'.", this.ServiceName , changeDescription.Reason);
            base.OnSessionChange(changeDescription);
        }
    }
}
